//-------------------------------------------------------------------
//	Copyright (c) 2010-2012  Zhirnov Andrey
//	This file is part of the "UXGEN" project.
//	See copyright notice in "Engine.h".
//-------------------------------------------------------------------

#ifndef _UX_RENDER_TYPES_H
#define _UX_RENDER_TYPES_H

#include "../Defines/Defines.h"

namespace Engine
{
namespace UXTypes
{

	typedef GLDEBUGPROCARB	PGLDebugProc_t;
	
#pragma pack(push, 1)


	//
	// Vertices Attribs
	//


	struct TVertexAttrib
	{
		uint					uOffset;
		uint16					uStride;
		uint16					uDivisor;
		gl_vertex::type			eType;
		e_vertex_attrib::type	eLocation;
		uint8					uCount;
		bool					bNormalize;
		///
		TVertexAttrib():
			uCount(0), uStride(0), uOffset(0), eType(gl_vertex::FLOAT), bNormalize(false), uDivisor(0),
			eLocation(e_vertex_attrib::LOCATION_0) {}
		
		TVertexAttrib(e_vertex_attrib::type loc, uint8 count, uint16 stride, uint offset, gl_vertex::type vert, bool norm, uint16 divisor = 0):
			uCount(count), uStride(stride), uOffset(offset), eType(vert), bNormalize(norm), uDivisor(divisor), eLocation(loc) {}
	};

	typedef array< TVertexAttrib >	TVerticesAttribs;



	//
	// VBO
	//

	struct TGLBuffer
	{
		GLuint				uIdent;
		gl_buffer::type		eTarget;
		///
		TGLBuffer(): uIdent(0), eTarget(gl_buffer::ARRAY) {}
		TGLBuffer(GLuint id, gl_buffer::type type): uIdent(id), eTarget(type) {}
	};

	typedef array< TGLBuffer >	TGLBufferBindings;



	//
	// Texture Layer
	//
	
	struct TGLTexLayer
	{
		gl_texture::type	eTarget;
		GLuint				uIdent;
		///
		TGLTexLayer(): eTarget(gl_texture::TEXTURE_2D), uIdent(0) {}
		TGLTexLayer(gl_texture::type target, GLuint id): eTarget(target), uIdent(id) {}
	};


	//
	// Texture Layer Extended
	//

	struct TGLTexLayerEx
	{
		gl_texture::type	eTarget;
		GLuint				uIdent,
							uSampler;
		///
		TGLTexLayerEx(): eTarget(gl_texture::TEXTURE_2D), uIdent(0), uSampler(0) {}
		TGLTexLayerEx(gl_texture::type target, GLuint id, GLuint sampler): eTarget(target), uIdent(id), uSampler(sampler) {}
	};


	//
	// Program Data
	//

	struct TProgramData
	{
		const void *	pData;
		usize			uSize;
		///
		TProgramData(): pData(nullptr), uSize(0) {}
		TProgramData(const void *data, usize size): pData(data), uSize(size) {}
		TProgramData(const binary_buffer_t &data): pData(data.ptr()), uSize(data.Size()) {}
		TProgramData(const float_array_t &data): pData(data.ptr()), uSize(data.Size()) {}

		template <typename T>
		TProgramData(const T &data): pData(&data), uSize(sizeof(T)) {}

		bool Valid() const
		{
			return ( pData != nullptr && uSize != 0 );
		}
	};


	//
	// Vertex 2D
	//

	struct TVertex2D
	{
		vec3		sPos,
					sTexCoord;
		color4u		sColor;
		///
		TVertex2D() {}
		TVertex2D(const vec2 &pos, const color4u &color = color4u()):  sPos(pos), sTexCoord(), sColor(color) {}	// point
		TVertex2D(const vec3 &pos, const color4u &color = color4u()):  sPos(pos), sTexCoord(), sColor(color) {} // point
		TVertex2D(const vec2 &pos, const vec2 &tex, const color4u &color = color4u()):  sPos(pos), sTexCoord(tex), sColor(color) {}
		TVertex2D(const vec3 &pos, const vec2 &tex, const color4u &color = color4u()):  sPos(pos), sTexCoord(tex), sColor(color) {}
	};


	//
	// Line 2D
	//

	struct TLine2D
	{
		TVertex2D	sPoint0,
					sPoint1;
		///
		TLine2D() {}
		TLine2D(const vec2 &p0, const vec2 &p1, const color4u &color = color4u()):  sPoint0(p0, color), sPoint1(p1, color) {}
		TLine2D(const vec3 &p0, const vec3 &p1, const color4u &color = color4u()):  sPoint0(p0, color), sPoint1(p1, color) {}
	};


	//
	// Triangle 2D
	//

	struct TTriangle2D
	{
		TVertex2D	sPoint0,
					sPoint1,
					sPoint2;
		///
		TTriangle2D() {}
		TTriangle2D(const TVertex2D &p0, const TVertex2D &p1, const TVertex2D &p2):  sPoint0(p0), sPoint1(p1), sPoint2(p2) {}
	};


	//
	// Quad 2D
	//

	struct TQuad2D
	{
		frect		sRect;
		frect		sTexCoord;
		color4u		sColor;
		float		fDepth;
		///
		TQuad2D() {}
		TQuad2D(const frect &pos, const frect &tex, const color4u &color = color4u(), float depth = 0.f):
			sRect(pos), sTexCoord(tex), sColor(color), fDepth(depth) {}
	};


	//
	// Rect 2D
	//

	struct TRect2D
	{
		TVertex2D	sPoint0,	// left bottom
					sPoint1,	// left top
					sPoint2,	// right top
					sPoint3;	// right bottom
		///
		TRect2D() {}
		TRect2D(const TQuad2D &q):
					sPoint0( vec3(q.sRect.x, q.sRect.y, q.fDepth), vec2(q.sTexCoord.x, q.sTexCoord.h), q.sColor ),
					sPoint1( vec3(q.sRect.x, q.sRect.h, q.fDepth), vec2(q.sTexCoord.x, q.sTexCoord.y), q.sColor ),
					sPoint2( vec3(q.sRect.w, q.sRect.y, q.fDepth), vec2(q.sTexCoord.w, q.sTexCoord.h), q.sColor ),
					sPoint3( vec3(q.sRect.w, q.sRect.h, q.fDepth), vec2(q.sTexCoord.w, q.sTexCoord.y), q.sColor ) {}

		TRect2D(const frect &pos, const frect &tex, const color4u aColors[4], float depth = 0.f):
					sPoint0( vec3(pos.x, pos.y, depth), vec2(tex.x, tex.h), aColors[0] ),
					sPoint1( vec3(pos.x, pos.h, depth), vec2(tex.x, tex.y), aColors[1] ),
					sPoint2( vec3(pos.w, pos.y, depth), vec2(tex.w, tex.h), aColors[2] ),
					sPoint3( vec3(pos.w, pos.h, depth), vec2(tex.w, tex.y), aColors[3] ) {}

		TRect2D(const TVertex2D &lt, const TVertex2D &lb, const TVertex2D &rb, const TVertex2D &rt):
					sPoint0(lt), sPoint1(lb), sPoint2(rt), sPoint3(rb) {}
	};


	//
	// Rect 2D (6 points)
	//

	struct TRect2D_6p
	{
		TTriangle2D	sTriangle0,		// lt, lb, rt
					sTriangle1;		// lb, rt, rb
		///
		TRect2D_6p() {}
		TRect2D_6p(const TRect2D &r):
					sTriangle0(r.sPoint0, r.sPoint1, r.sPoint2),
					sTriangle1(r.sPoint1, r.sPoint2, r.sPoint3) {}
		TRect2D_6p(const TTriangle2D &t0, const TTriangle2D &t1):
					sTriangle0(t0), sTriangle1(t1) {}
	};


	//
	// Vertex 3D
	//

	struct TVertex3D
	{
		vec3		sPos,
					sNormal;
		vec2		sTexCoord;
		///
		TVertex3D() {}
		TVertex3D(const vec3 &pos, const vec2 &tex = vec2(), const vec3 &normal = vec3()):  sPos(pos), sTexCoord(tex), sNormal(normal) {}
	};


	//
	// Line 3D
	//

	struct TLine3D
	{
		TVertex3D	sPoint0,
					sPoint1;
		///
		TLine3D() {}
		TLine3D(const vec3 &p0, const vec3 &p1):  sPoint0(p0), sPoint1(p1) {}
	};


	//
	// Triangle 3D
	//

	struct TTriangle3D
	{
		TVertex3D	sPoint0,
					sPoint1,
					sPoint2;
		///
		TTriangle3D() {}
		TTriangle3D(const TVertex3D &p0, const TVertex3D &p1, const TVertex3D &p2):  sPoint0(p0), sPoint1(p1), sPoint2(p2) {}
	};


	//
	// Rect 3D
	//

	struct TRect3D
	{
		TVertex3D	sPoint0,	// left top
					sPoint1,	// left bottom
					sPoint2,	// right top
					sPoint3;	// right bottom
		///
		TRect3D() {}

		TRect3D(const frect &pos, const frect &tex, const vec3 &normal, float depth = 0.f):
					sPoint0( vec3(pos.x, pos.y, depth), vec2(tex.x, tex.h), normal ),
					sPoint1( vec3(pos.x, pos.h, depth), vec2(tex.x, tex.y), normal ),
					sPoint2( vec3(pos.w, pos.y, depth), vec2(tex.w, tex.h), normal ),
					sPoint3( vec3(pos.w, pos.h, depth), vec2(tex.w, tex.y), normal ) {}

		TRect3D(const TVertex3D &lt, const TVertex3D &lb, const TVertex3D &rb, const TVertex3D &rt):
					sPoint0(lt), sPoint1(lb), sPoint2(rt), sPoint3(rb) {}
	};

#pragma pack(pop)



	//
	// Base Material interface
	//

	class IBaseMaterial
	{
	public:
		virtual void					Apply() = 0;
		virtual e_render_layer::type	GetRenderLayer() const = 0;
	};

//-------------------------------------------------------------------

}	// UXTypes
}	// Engine

#endif	// _UX_RENDER_TYPES_H